package com.liuyk.controller;

import android.content.Context;
import android.graphics.Bitmap;
import android.media.MediaMetadataRetriever;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
import android.util.Log;

import com.github.hiteshsondhi88.libffmpeg.ExecuteBinaryResponseHandler;
import com.github.hiteshsondhi88.libffmpeg.FFmpeg;
import com.github.hiteshsondhi88.libffmpeg.LoadBinaryResponseHandler;
import com.github.hiteshsondhi88.libffmpeg.exceptions.FFmpegNotSupportedException;

import java.io.File;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 视频压缩
 * <p>
 * Created by Liuyk on 2017/8/30.
 */
public class CompressController {
    public static final String DEFAULT_OUT_PATH = "Compress/OutVideo";
    public static final String DEFAULT_IN_PATH = "Compress/InVideo";
    public static final String TAG = "CompressController";
    private static volatile CompressController instance;
    private final FFmpeg ffmpeg;

    private CompressController(Context context) {
        ffmpeg = FFmpeg.getInstance(context);
        try {
            ffmpeg.loadBinary(new LoadBinaryResponseHandler() {

                @Override
                public void onStart() {
                }

                @Override
                public void onFailure() {
                }

                @Override
                public void onSuccess() {
                }

                @Override
                public void onFinish() {
                }
            });
        } catch (FFmpegNotSupportedException e) {
            // Handle if FFmpeg is not supported by device
            e.printStackTrace();
        }
    }

    public static synchronized CompressController getInstance(Context context) {
        if (instance == null) {
            instance = new CompressController(context);
        }
        return instance;
    }

    public void compress(String inPath, final CompressCallBack callBack) {
        if (TextUtils.isEmpty(inPath)) {
            callBack.onCompressFail("file not exists");
            return;
        }
        compress(inPath, null, callBack);
    }

    public void compress(String inPath, String outPath, final CompressCallBack callBack) {
        compress(inPath, outPath, false, callBack);
    }

    public void compress(String inPath, String outPath, boolean isDelOriginalFile, final CompressCallBack callBack) {
        final File file = new File(inPath);
        if (!file.exists()) {
            callBack.onCompressFail("file not exists");
            return;
        }
        if (TextUtils.isEmpty(outPath)) {
            outPath = getCompressOutPath(file.getName());
        }
        final String cmd = getCompressCommand(inPath, outPath);
        executeCompress(cmd, isDelOriginalFile, file, callBack);
    }

    private void executeCompress(String cmd, final boolean isDelOriginalFile, final File oriFile, final CompressCallBack callBack) {
        try {
            String[] cmds = cmd.split(" ");
            ffmpeg.execute(cmds, new ExecuteBinaryResponseHandler() {
                @Override
                public void onSuccess(final String message) {
                    Log.i(TAG, "success " + message);
                    if (isDelOriginalFile) {
                        oriFile.delete();
                    }
                    runMain(new Runnable() {
                        @Override
                        public void run() {
                            callBack.onCompressSuccess(message);
                        }
                    });
                }

                @Override
                public void onProgress(final String message) {
                    Log.i(TAG, "progress " + message);
                    runMain(new Runnable() {
                        @Override
                        public void run() {
                            callBack.onCompressProgress(message);
                        }
                    });
                }

                @Override
                public void onFailure(final String reason) {
                    Log.i(TAG, "fail " + reason);
                    runMain(new Runnable() {
                        @Override
                        public void run() {
                            callBack.onCompressFail(reason);
                        }
                    });
                }

                @Override
                public void onStart() {

                }

                @Override
                public void onFinish() {

                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private String getCompressCommand(String inPath, String outPath) {
        Bitmap videoThumbnail = getVideoThumbnail(inPath);
        final int videoW = videoThumbnail.getWidth();
        final int videoH = videoThumbnail.getHeight();
        final String cmd = "-y -i " + inPath + " -strict -2 -vcodec libx264 -preset ultrafast " +
                "-crf 24 -acodec aac -ar 44100 -ac 2 -b:a 96k -s " + videoW + "x" + videoH + " -aspect 16:9 " +
                outPath;
        return cmd;
    }

    public int getProgress(String source, int videoDuration) {
        //progress frame=   28 fps=0.0 q=24.0 size= 107kB time=00:00:00.91 bitrate= 956.4kbits/s
        Pattern p = Pattern.compile("00:\\d{2}:\\d{2}");
        Matcher m = p.matcher(source);
        if (m.find()) {
            //00:00:00
            String result = m.group(0);
            String[] temp = result.split(":");
            int seconds = (int) (Double.parseDouble(temp[1]) * 60 + Double.parseDouble(temp[2]));
            Log.v(TAG, "current second = " + seconds);
            if (0 != videoDuration) {
                return seconds / videoDuration;
            }
            return 0;
        }
        return 0;
    }

    public double getVideoDuration(String videoPath) {
        final MediaMetadataRetriever retr = new MediaMetadataRetriever();
        retr.setDataSource(videoPath);
        String time = retr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);//获取视频时长
        try {
            return Double.parseDouble(time) / 1000.00;
        } catch (Exception e) {
            e.printStackTrace();
            return 0.00;
        }
    }

    public String getCompressOutPath(String name) {
        final File file = new File(Environment.getExternalStorageDirectory(), DEFAULT_OUT_PATH);
        if (!file.exists()) {
            file.mkdirs();
        }
        return new File(file.getAbsolutePath(), name).getAbsolutePath();
    }

    public String getCompressInPath(String name) {
        final File file = new File(Environment.getExternalStorageDirectory(), DEFAULT_IN_PATH);
        if (!file.exists()) {
            file.mkdirs();
        }
        return new File(file.getAbsolutePath(), name).getAbsolutePath();
    }

    //视频第一帧缩略图
    public static Bitmap getVideoThumbnail(String videoPath) {
        final MediaMetadataRetriever media = new MediaMetadataRetriever();
        media.setDataSource(videoPath);
        return media.getFrameAtTime();
    }

    public interface CompressCallBack {
        void onCompressSuccess(String message);

        void onCompressFail(String message);

        void onCompressProgress(String message);
    }

    public void runMain(Runnable runnable) {
        new Handler(Looper.getMainLooper()).post(runnable);
    }
}
